'''
Created on 28/03/2014

@author: jpfuertes
'''

import notes

class Position():
    
    def __init__(self,string,fret):
        self.string = string
        self.fret = fret
        
    def __cmp__(self,other):
        return cmp((self.string,self.fret),(other.string,other.fret))
    
    def __repr__(self):
        return 'Chord:%s Fret:%s (%s,%s)' % (self.string + 1,self.fret, self.string, self.fret)
    
    def __str__(self):
        return repr(self)
    
    
class PositionWithOctaveOffset():
    
    def __init__(self,position,octave_offset):
        self.position = position
        self.octave_offset = octave_offset
        
    def __cmp__(self,other):
        return cmp((self.position,self.octave_offset),(other.position,other.octave_offset))
    
    def __repr__(self):
        return '%s at %s octaves' % (self.position,self.octave_offset)
    
    def __str__(self):
        return repr(self)
    
    

class IString:
    
    def __init__(self,note,frets):
        self.__notes = [note]
        for x in range(frets):        
            note = note.next()
            self.__notes.append(note)        
        
    def get(self,fret):
        return self.__notes[fret]
    
    def find_similar(self,note):
        frets = []
        for x in range(len(self.__notes)):
            similar = self.__notes[x].similar_note(note)
            if similar is not None:
                frets.append([x,similar])
        return frets
    
    def __str__(self):
        return ''.join([str(x) for x in self.__notes]) + '\n'
        
    def __repr__(self):
        return ''.join([str(x) for x in self.__notes]) + '\n'
        
            
                
                
class ChordInstrument(object):

    def get(self,position):        
        try:
            return self.strings[position.string].get(position.fret)
        except:
            print position
            print self
            raise
    
    def find(self,note):
        positions = []
        for idx in range(len(self.strings)):
            similars = self.strings[idx].find_similar(note)
            for fret,similarity in similars: 
                pos = PositionWithOctaveOffset(Position(idx,fret),similarity)
                positions.append(pos)
                
        sorted_positions = sorted(positions,key=lambda x: x.octave_offset)
        return sorted_positions
    
    def __str__(self):
        return """%s
        %s
        """ % (self.NAME,self.strings)            
    

class Charango(ChordInstrument):
    '''
    This class represents a Charango.
    '''
    NAME = 'Charango'
    FRETS = 20  
    
    def __init__(self):        
        self.strings = [
            IString(notes.E(5),self.FRETS),            
            IString(notes.A(4),self.FRETS),            
            IString(notes.E(4),self.FRETS),
            IString(notes.C(5),self.FRETS),
            IString(notes.G(4),self.FRETS),
            ]

class Guitarra(ChordInstrument):
    '''
    This class represents a Charango.
    '''
    FRETS = 20  
    NAME = 'Guitarra'
    
    def __init__(self):
        self.strings = [
            IString(notes.E(4),self.FRETS),
            IString(notes.B(3),self.FRETS),
            IString(notes.G(3),self.FRETS),
            IString(notes.D(3),self.FRETS),
            IString(notes.A(2),self.FRETS),
            IString(notes.E(2),self.FRETS),
            ]
